#include "bcomdef.h"
#include "OSAL.h"
#include "linkdb.h"
#include "att.h"
#include "gatt.h"
#include "gatt_uuid.h"
#include "gattservapp.h"
#include "MyProfile.h"

//service UUID array
CONST uint8 myServiceUUID[2] = 
{
  LO_UINT16(MY_SERVICE_UUID), HI_UINT16(MY_SERVICE_UUID)
};
//move UUID array
CONST uint8 charMoveUUID[2] = 
{
  LO_UINT16(CHAR_MOVE_UUID), HI_UINT16(CHAR_MOVE_UUID)
};
//spin UUID array
CONST uint8 charSpinUUID[2] = 
{
  LO_UINT16(CHAR_SPIN_UUID), HI_UINT16(CHAR_SPIN_UUID)
};
//servive attribute
static CONST gattAttrType_t myService = { 2, myServiceUUID };
//movement and spining characteristic properties
static uint8 moveCharProps = GATT_PROP_NOTIFY;
static uint8 spinCharProps = GATT_PROP_NOTIFY;
//初始值
static uint8 moveCharValue[CHAR_LEN_BYTES] = {0,0};
static uint8 spinCharValue[CHAR_LEN_BYTES] = {0,0};
//config对象 用来通过蓝牙的方式改写数据 service 与 client 同时更改
static gattCharCfg_t moveCharConfig[GATT_MAX_NUM_CONN];
static gattCharCfg_t spinCharConfig[GATT_MAX_NUM_CONN];
//描述符
static uint8 moveCharDesc[11] = "move speed\0";
static uint8 spinCharDesc[11] = "spin angle\0";


static uint8 readAttrCB( uint16 connHandle, gattAttribute_t *pAttr, 
                            uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen );
static bStatus_t writeAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                                 uint8 *pValue, uint8 len, uint16 offset );
static void handleConnStatusCB( uint16 connHandle, uint8 changeType );

CONST gattServiceCBs_t CBs =
{
  readAttrCB, 
  writeAttrCB,
  NULL    
};

//Attribute Table
static gattAttribute_t myAttrTable[5] = 
{
  {
    { 2, primaryServiceUUID },
    GATT_PERMIT_READ,
    0,
    (uint8*)&myService
  },
    //移动速度 character 的声明是 notify
    { 
      { 2, characterUUID },
      GATT_PERMIT_READ,
      0,
      &moveCharProps
    },
    //移动速度 character 的值
    { 
      { 2, charMoveUUID },
      0,
      0,
      moveCharValue
    },
    //移动速度 character 的配置 用来通过 notify 更改数据
    { 
      { 2, clientCharCfgUUID },
      GATT_PERMIT_READ | GATT_PERMIT_WRITE,
      0,
      (uint8*)moveCharConfig
    },
    //移动速度 character 的描述符
    { 
      { 2, charUserDescUUID },
      GATT_PERMIT_READ,
      0,
      moveCharDesc
    }
};


bStatus_t addServiceToGatt() 
{
  GATTServApp_InitCharCfg( INVALID_CONNHANDLE, moveCharConfig );
  
  VOID linkDB_Register( handleConnStatusCB );

  return GATTServApp_RegisterService( myAttrTable, 
                               GATT_NUM_ATTRS(myAttrTable), 
                               &CBs);
}

static void handleConnStatusCB( uint16 connHandle, uint8 changeType )
{ 
  if ( connHandle != LOOPBACK_CONNHANDLE )
  {
    if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED )      ||
         ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && 
           ( !linkDB_Up( connHandle ) ) ) )
    { 
      GATTServApp_InitCharCfg( connHandle, moveCharConfig );
    }
  }
}
  
  
static uint8 readAttrCB( uint16 connHandle, gattAttribute_t *pAttr, 
                            uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen )
{
  bStatus_t status = SUCCESS;
  if ( offset > 0 )
  {
    return ( ATT_ERR_ATTR_NOT_LONG );
  }
 
  if ( pAttr->type.len == ATT_BT_UUID_SIZE )
  {
    // 16-bit UUID
    uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
    switch ( uuid )
    {
      case CHAR_MOVE_UUID:
        *pLen = CHAR_LEN_BYTES;
        VOID osal_memcpy( pValue, pAttr->pValue, CHAR_LEN_BYTES );
        break;

      default:
        *pLen = 0;
        status = ATT_ERR_ATTR_NOT_FOUND;
        break;
    }
  }
  else
  {
    // 128-bit UUID
    *pLen = 0;
    status = ATT_ERR_INVALID_HANDLE;
  }

  return ( status );
}


static bStatus_t writeAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                                 uint8 *pValue, uint8 len, uint16 offset )
{
  bStatus_t status = SUCCESS;

  if ( pAttr->type.len == ATT_BT_UUID_SIZE )
  {
    // 16-bit UUID
    uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
    switch ( uuid )
    {
      case GATT_CLIENT_CHAR_CFG_UUID:
        status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
                                                 offset, GATT_CLIENT_CFG_NOTIFY );
        break;
       
      default:
        status = ATT_ERR_ATTR_NOT_FOUND;
        break;
    }
  }
  else
  {
    // 128-bit UUID
    status = ATT_ERR_INVALID_HANDLE;
  }

  return ( status );
}


bStatus_t notifiySpeed(void *pValue)
{

  moveCharValue[0] = *((uint8*)pValue);
  moveCharValue[1] = *(((uint8*)pValue)+1);
 
  
  return GATTServApp_ProcessCharCfg( moveCharConfig, moveCharValue, FALSE, 
                              myAttrTable, GATT_NUM_ATTRS( myAttrTable ),
                              INVALID_TASK_ID );

}
